<?php

namespace app\index\service;

use app\admin\service\PersonnelService;
use app\common\model\AccessLog;
use app\common\model\Account;
use app\common\model\AccountBill;
use app\common\model\CashTransfer;
use app\common\model\Consulting;
use app\common\model\ConsultingComment;
use app\common\model\ConsultingIgnore;
use app\common\model\ConsultingMessage;
use app\common\model\ConsultingQuestion;
use app\common\model\ConsultingSubsidy;
use app\common\model\Member;
use app\common\model\MemberCategoryRel;
use app\common\model\MemberInfo;
use app\common\model\MemberInvite;
use app\common\model\Trade;
use app\common\model\Transfer;
use app\index\traits\SessionMemberDraftTrait;
use ShidianUtil\Utils\StringUtil;
use think\exception\ValidateException;
use think\facade\Config;
use think\facade\Log;

/**
 * 用户登录抽象类
 * Class AbstractSessionService
 * @package app\index\service
 */
abstract class AbstractSessionService
{
    use SessionMemberDraftTrait;

    /**
     * @param string $unionidKey 三方平台唯一ID的key
     * @param string $unionid 三方平台唯一ID
     * @param string $phone 手机号
     * @param array $memberParams 用户信息
     * @param array $bindKeys 三方平台身份信息字段
     * @return Member
     */
    protected function findMember($unionidKey, $unionid, $phone, array $memberParams, array $bindKeys)
    {
        $member = Member::where($unionidKey, $unionid)
            ->whereIn('status', [0, 1])
            ->order('id', 'ASC')
            ->find();

        $test = Config::get('member.testAccount', []);

        if (is_null($member)) {
            // uninid 未注册

            // 查询手机号是否可以绑定
            $phoneMember = Member::where('phone', $phone)
                ->whereIn('status', [0, 1])
                ->whereNotIn('phone', $test)
                ->find();
            if ($phoneMember) {
                // 该手机号已注册

                if (is_blank($phoneMember->$unionidKey)) {
                    // 该手机号未绑定第三方信息

                    // 绑定第三方信息
                    $this->bindUnionid($phoneMember, $memberParams, $bindKeys);

                    // 登录账号
                    $member = $phoneMember;
                } else {
                    // 该手机号已绑定第三方信息

                    Log::warning('unionid = ' . $unionid);

                    throw new ValidateException('该手机号已绑定其他账号，请使用原账号登录');
                }
            } else {
                //  该手机号未注册

                // 注册新用户账号 && 绑定第三方信息
                $member = $this->getMemberService()->add($memberParams);
            }

        } else {
            // uninid 已注册

            // 查询相同unionid账号
            Member::where($unionidKey, $unionid)
                ->whereIn('status', [0, 1])
                ->order('id', 'ASC')
                ->where('id', '<>', $member->id)
                ->whereNotIn('phone', $test)
                ->select()
                ->each(function (Member $sameMember) use ($member) {
                    // 合并账号
                    $this->memberMerge($member, $sameMember);
                });

            //  判断手机号是否一致
            if (is_blank($member->phone)) {
                // 该uninid账号未绑定手机号

                // 查询手机号是否可以绑定
                $phoneMember = Member::where('phone', $phone)
                    ->whereIn('status', [0, 1])
                    ->where('id', '<>', $member->id)
                    ->whereNotIn('phone', $test)
                    ->find();
                if ($phoneMember) {
                    // 该手机号已注册

                    if (is_blank($phoneMember->$unionidKey)) {
                        // 该手机号账号未绑定第三方信息

                        // 合并账号
                        $this->memberMerge($phoneMember, $member);

                        // 登录账号
                        $member = $phoneMember;
                    } else {
                        // 该手机号账号已绑定第三方信息

                        Log::warning('unionid = ' . $unionid);

                        throw new ValidateException('该手机号已绑定其他账号，请使用原账号登录');
                    }
                } else {
                    // 该手机号未注册

                    // 绑定手机号
                    $this->bindPhone($member, $phone);
                }
            } elseif (StringUtil::equals($phone, $member->phone)) {
                // 手机号一致

                // 查询手机号是否可以绑定
                $phoneMember = Member::where('phone', $phone)
                    ->whereIn('status', [0, 1])
                    ->where('id', '<>', $member->id)
                    ->whereNotIn('phone', $test)
                    ->find();
                if ($phoneMember) {
                    // 该手机号绑定了其他账号

                    // 该手机号账号未绑定第三方信息
                    if (is_blank($phoneMember->$unionidKey)) {

                        // 合并账号
                        $this->memberMerge($member, $phoneMember);
                    }
                }
            } elseif (!StringUtil::equals($phone, $member->phone)) {
                // 手机号不同

                // 报错，手机号已被绑定
                $tempPhone = substr_replace($member->phone, '****', 3, 4);
                throw new ValidateException('请使用原手机号' . $tempPhone . '登录');
            }

            // 登录成功

            // 修改用户模型
            $member = $this->getMemberService()->modify($member->id, $memberParams);
        }

        return $member;
    }

    /**
     * 绑定三方登录信息
     * @param Member $member
     * @param array $memberParams
     * @param array $bindKeys
     * @return void
     */
    protected function bindUnionid(Member $member, $memberParams, array $bindKeys): void
    {
        if (empty($bindKeys)) {
            return;
        }

        foreach ($bindKeys as $key) {
            if (isset($memberParams[$key])) {
                $member->$key = $memberParams[$key];
            }
        }

        $member->save();
    }

    /**
     * 账号合并
     * @param Member $reservedMember 保留的账号（保留有手机号的账号）
     * @param Member $mergeMember 被合并账号
     * @return void
     */
    protected function memberMerge(Member $reservedMember, Member $mergeMember)
    {
        $reservedMemberId = $reservedMember->id;
        $mergeMemberId = $mergeMember->id;

        if ($reservedMemberId == $mergeMemberId) {
            return;
        }

        // TODO 这里加个同步，然后判断一下状态，防止重复合并

        // 冻结被合并账号
        $this->getMemberService()->memberStatusChange($mergeMember, 2);

        // 合并三方登录信息
        foreach (Member::UNIONID_ARR as $key) {
            if (not_blank($mergeMember->$key)) {
                $reservedMember->$key = $mergeMember->$key;
            }
        }

        // 合并头像，昵称，城市，邀请信息，禁言
        if ($reservedMember->wanzhengTouxiang == 0 && $mergeMember->wanzhengTouxiang == 1) {
            $reservedMember->headImgUrl = $mergeMember->headImgUrl;
            $reservedMember->wanzhengTouxiang = $mergeMember->wanzhengTouxiang;
        }
        if ($reservedMember->wanzhengNicheng == 0 && $mergeMember->wanzhengNicheng == 1) {
            $reservedMember->nickname = $mergeMember->nickname;
            $reservedMember->wanzhengNicheng = $mergeMember->wanzhengNicheng;
        }
        if ($mergeMember->muted != 1) {
            $reservedMember->muted = $mergeMember->muted;
            $reservedMember->mutedLength = $mergeMember->mutedLength;
            $reservedMember->mutedTime = $mergeMember->mutedTime;
            $reservedMember->mutedCause = $mergeMember->mutedCause;
            $reservedMember->mutedUserId = $mergeMember->mutedUserId;
            $reservedMember->mutedActionTime = $mergeMember->mutedActionTime;
            $reservedMember->disabledUserId = $mergeMember->disabledUserId;
            $reservedMember->disabledActionTime = $mergeMember->disabledActionTime;
        }
        if ($reservedMember->provinceId == 0 && $mergeMember->provinceId != 0) {
            $reservedMember->provinceId = $mergeMember->provinceId;
        }
        if ($reservedMember->cityId == 0 && $mergeMember->cityId != 0) {
            $reservedMember->cityId = $mergeMember->cityId;
        }
        if ($reservedMember->isInviter == 0 && $mergeMember->isInviter != 0) {
            $reservedMember->isInviter = $mergeMember->isInviter;
        }
        if ($reservedMember->inviterTime == 0 && $mergeMember->inviterTime != 0) {
            $reservedMember->inviterTime = $mergeMember->inviterTime;
        }
        if (is_blank($reservedMember->inviteCode) && not_blank($mergeMember->inviteCode)) {
            $reservedMember->inviteCode = $mergeMember->inviteCode;
        }

        $reservedMember->save();

        //  如果是律师（如果任一账号是律师，那么身份就是律师）
        if ($mergeMember->type == 1) {

            if ($reservedMember->type != 1) {
                // 合并律师信息 用户类型type，真实姓名，接单状态
                $reservedMember->type = $mergeMember->type;
                $reservedMember->isSettled = $mergeMember->isSettled;
                $reservedMember->settledTime = $mergeMember->settledTime;
                $reservedMember->realname = $mergeMember->realname;
                $reservedMember->matchStatus = $mergeMember->matchStatus;
                $reservedMember->save();

                // 合并 member_info表
                try {
                    MemberInfo::where('memberId', $mergeMemberId)
                        ->update(['memberId' => $reservedMemberId]);
                } catch (\Exception $exception) {
                    // 以防万一，保留账号有律师信息，会报错
                }
            }

            // 合并擅长领域
            $categoriesIds = MemberCategoryRel::where('memberId', $mergeMemberId)->select()->column('categoryId');
            $memberInfo = MemberInfo::where('memberId', $reservedMemberId)->field(['memberId'])->find();
            if ($memberInfo && !empty($categoriesIds)) {
                $memberInfo->categories()->attach($categoriesIds);
            }

            // 合并他回答的咨询
            Consulting::where('lawyerId', $mergeMemberId)
                ->update(['lawyerId' => $reservedMemberId]);

            // 合并咨询内收到的补贴
            ConsultingSubsidy::where('lawyerId', $mergeMemberId)
                ->update(['lawyerId' => $reservedMemberId]);

            // 回答的热门咨询
            ConsultingQuestion::where('lawyerId', $mergeMemberId)
                ->update(['lawyerId' => $reservedMemberId]);

            // 合并咨询忽略记录
            try {
                ConsultingIgnore::where('lawyerId', $mergeMemberId)
                    ->update(['lawyerId' => $reservedMemberId]);
            } catch (\Exception $exception) {

            }

            // 合并被评价记录
            ConsultingComment::where('lawyerId', $mergeMemberId)
                ->update(['lawyerId' => $reservedMemberId]);

        }


        // 合并发起的咨询
        Consulting::where('memberId', $mergeMemberId)
            ->update(['memberId' => $reservedMemberId]);

        // 咨询下聊天记录
        ConsultingMessage::where('senderId', $mergeMemberId)
            ->update(['senderId' => $reservedMemberId]);
        ConsultingMessage::where('receiveId', $mergeMemberId)
            ->update(['receiveId' => $reservedMemberId]);

        // 合并咨询内补贴
        ConsultingSubsidy::where('memberId', $mergeMemberId)
            ->update(['memberId' => $reservedMemberId]);

        // 合并咨询提问记录
        ConsultingQuestion::where('memberId', $mergeMemberId)
            ->update(['memberId' => $reservedMemberId]);

        // 合并发起的评价
        ConsultingComment::where('memberId', $mergeMemberId)
            ->update(['memberId' => $reservedMemberId]);


        // 合并余额账户
        if ($mergeMember->account && $mergeMember->account->balance > 0) {
            Account::where('memberId', $reservedMemberId)
                ->where('payMethod', PAYMENT_ACCOUNT)
                ->inc('balance', $mergeMember->account->balance)
                ->update();
        }
        // 合并获客卡账户
        if ($mergeMember->card && $mergeMember->card->balance > 0) {
            Account::where('memberId', $reservedMemberId)
                ->where('payMethod', PAYMENT_CARD)
                ->inc('balance', $mergeMember->card->balance)
                ->update();
        }
        // 合并通信币
        if ($mergeMember->coin && $mergeMember->coin->balance > 0) {
            Account::where('memberId', $reservedMemberId)
                ->where('payMethod', PAYMENT_COIN)
                ->inc('balance', $mergeMember->coin->balance)
                ->update();
        }

        // 合并账单记录
        AccountBill::where('fromMemberId', $mergeMemberId)
            ->where('fromType', 'member')
            ->update(['fromMemberId' => $reservedMemberId]);
        AccountBill::where('toMemberId', $mergeMemberId)
            ->where('toType', 'member')
            ->update(['toMemberId' => $reservedMemberId]);

        // 合并提现申请记录
        CashTransfer::where('memberId', $mergeMemberId)
            ->update(['memberId' => $reservedMemberId]);

        // 合并订单
        Trade::where('memberId', $mergeMemberId)
            ->update(['memberId' => $reservedMemberId]);

        // 合并转账
        Transfer::where('memberId', $mergeMemberId)
            ->update(['memberId' => $reservedMemberId]);

        // 合并邀请信息
        try {
            MemberInvite::where('memberId', $mergeMemberId)
                ->update(['memberId' => $reservedMemberId]);
        } catch (\Exception $exception) {
        }
        try {
            MemberInvite::where('memberIdInvite', $mergeMemberId)
                ->update(['memberIdInvite' => $reservedMemberId]);
        } catch (\Exception $exception) {
        }

        // 合并访问记录
        AccessLog::where('memberId', $mergeMemberId)
            ->update(['memberId' => $reservedMemberId]);
    }

    // 绑定手机号
    protected function bindPhone(Member $member, $phone)
    {
        $member->phone = $phone;
        $member->modPhoneTime = time();
        $member->save();

        $this->getPersonnelService()->bindPersonnel($member);
    }

    protected function checkMemberStatus(Member $member): void
    {
        if ($member->status == 1) {
            return;
        }

        // 是否冻结
        if ($member->status == 0) {
            throw new ValidateException('由于您的违规操作，您的账号已被冻结');
        }

        // 是否被合并
        if ($member->status == 2) {
            throw new ValidateException('该账号已被合并到新账号');
        }

        throw new ValidateException('账号状态异常，请联系客服');
    }

    protected function getMemberService(): MemberService
    {
        return app(MemberService::class);
    }

    private function getPersonnelService(): PersonnelService
    {
        return app(PersonnelService::class);
    }

}
